#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
七牛云图片上传模块
适用于MaixCAM嵌入式设备
"""

import requests
import json
import time
import hashlib
import base64
import hmac
from urllib.parse import urlparse
from datetime import datetime


class QiniuUploader:
    """七牛云上传器"""
    
    def __init__(self, access_key, secret_key, bucket_name, domain):
        """
        初始化七牛云上传器
        
        Args:
            access_key (str): 七牛云Access Key
            secret_key (str): 七牛云Secret Key
            bucket_name (str): 存储空间名称
            domain (str): 存储空间域名
        """
        self.access_key = access_key
        self.secret_key = secret_key
        self.bucket_name = bucket_name
        self.domain = domain
        self.upload_url = "https://up-z2.qiniup.com"  # 七牛云上传地址（华南地区）
        
    def _generate_upload_token(self, key=None, expires=3600):
        """
        生成上传凭证
        
        Args:
            key (str, optional): 指定文件名
            expires (int): 凭证过期时间（秒）
            
        Returns:
            str: 上传凭证
        """
        # 构造上传策略
        put_policy = {
            "scope": self.bucket_name + (":" + key if key else ""),
            "deadline": int(time.time()) + expires
        }
        
        # 将策略转换为JSON并进行Base64编码
        put_policy_json = json.dumps(put_policy, separators=(',', ':'))
        encoded_put_policy = base64.urlsafe_b64encode(put_policy_json.encode('utf-8')).decode('utf-8')
        
        # 使用HMAC-SHA1算法计算签名
        signature = hmac.new(
            self.secret_key.encode('utf-8'),
            encoded_put_policy.encode('utf-8'),
            hashlib.sha1
        ).digest()
        
        # 对签名进行Base64编码
        encoded_signature = base64.urlsafe_b64encode(signature).decode('utf-8')
        
        # 拼接上传凭证
        upload_token = f"{self.access_key}:{encoded_signature}:{encoded_put_policy}"
        return upload_token
        
    def upload_image(self, image_path, name=None):
        """
        上传图片到七牛云，按年月日结构存储，并包含小时信息
        
        Args:
            image_path (str): 本地图片路径
            name (str, optional): 文件名前缀，如果为None则使用默认名称
            
        Returns:
            dict: 上传结果
                成功: {"success": True, "key": "文件名", "hash": "文件hash", "url": "访问URL"}
                失败: {"success": False, "error": "错误信息"}
        """
        try:
            # 生成带日期结构的文件名（包含小时信息）
            now = datetime.now()
            date_path = now.strftime("aky/%Y/%m/%d")  # 日期路径
            hour_prefix = now.strftime("%H")  # 小时信息
            
            if name:
                # 使用提供的名称作为前缀，加上小时信息
                filename = f"{date_path}/{hour_prefix}+{name}.jpg"
            else:
                # 使用时间戳作为文件名，加上小时信息
                timestamp = int(now.timestamp())
                filename = f"{date_path}/{hour_prefix}+image_{timestamp}.jpg"
            
            # 生成上传凭证
            token = self._generate_upload_token(filename)
            
            # 准备上传数据
            with open(image_path, 'rb') as f:
                file_data = f.read()
            
            # 构造表单数据
            files = {
                'file': (filename, file_data)
            }
            data = {
                'token': token,
                'key': filename  # 指定文件名，实现覆盖模式
            }
            
            # 发送上传请求
            response = requests.post(self.upload_url, files=files, data=data)
            
            # 处理响应
            if response.status_code == 200:
                result = response.json()
                # 生成访问URL
                url = f"http://{self.domain}/{result.get('key')}"
                return {
                    "success": True,
                    "key": result.get("key"),
                    "hash": result.get("hash"),
                    "url": url
                }
            else:
                return {
                    "success": False,
                    "error": f"上传失败，状态码: {response.status_code}, 响应: {response.text}"
                }
                
        except FileNotFoundError:
            return {
                "success": False,
                "error": f"文件未找到: {image_path}"
            }
        except Exception as e:
            return {
                "success": False,
                "error": f"上传异常: {str(e)}"
            }
            
    def upload_image_data(self, image_data, name=None):
        """
        上传图片数据到七牛云，按年月日结构存储，并包含小时信息
        
        Args:
            image_data (bytes): 图片二进制数据
            name (str, optional): 文件名前缀，如果为None则使用默认名称
            
        Returns:
            dict: 上传结果
                成功: {"success": True, "key": "文件名", "hash": "文件hash", "url": "访问URL"}
                失败: {"success": False, "error": "错误信息"}
        """
        try:
            # 生成带日期结构的文件名（包含小时信息）
            now = datetime.now()
            date_path = now.strftime("aky/%Y/%m/%d")  # 日期路径
            hour_prefix = now.strftime("%H")  # 小时信息
            
            if name:
                # 使用提供的名称作为前缀，加上小时信息
                filename = f"{date_path}/{hour_prefix}+{name}.jpg"
            else:
                # 使用时间戳作为文件名，加上小时信息
                timestamp = int(now.timestamp())
                filename = f"{date_path}/{hour_prefix}+image_{timestamp}.jpg"
            
            # 生成上传凭证
            token = self._generate_upload_token(filename)
            
            # 构造表单数据
            files = {
                'file': (filename, image_data)
            }
            data = {
                'token': token,
                'key': filename  # 指定文件名，实现覆盖模式
            }
            
            # 发送上传请求
            response = requests.post(self.upload_url, files=files, data=data)
            
            # 处理响应
            if response.status_code == 200:
                result = response.json()
                # 生成访问URL
                url = f"http://{self.domain}/{result.get('key')}"
                return {
                    "success": True,
                    "key": result.get("key"),
                    "hash": result.get("hash"),
                    "url": url
                }
            else:
                return {
                    "success": False,
                    "error": f"上传失败，状态码: {response.status_code}, 响应: {response.text}"
                }
                
        except Exception as e:
            return {
                "success": False,
                "error": f"上传异常: {str(e)}"
            }


def example():
    """使用示例"""
    # 七牛云配置信息
    ACCESS_KEY = "KgCzxHSGM7pTsrTZbQptzoow42e5IcFOMeFrIoQz"
    SECRET_KEY = "xcloaEa4X3XzqXKDmz_1U1AFtNI1jlbodaHoNOQ4"
    BUCKET_NAME = "hongkongidcard"
    DOMAIN = "hongkongidcard.wenfree.cn"
    
    # 创建上传器实例
    uploader = QiniuUploader(ACCESS_KEY, SECRET_KEY, BUCKET_NAME, DOMAIN)
    
    # 上传本地图片文件，使用指定名称
    result = uploader.upload_image("/tmp/current_frame.jpg", "idcard_image")
    if result["success"]:
        print(f"上传成功! 文件名: {result['key']}, Hash: {result['hash']}")
        print(f"访问地址: {result['url']}")
    else:
        print(f"上传失败: {result['error']}")

def integrate_with_camera_example():
    """
    与摄像头功能集成的示例
    展示如何在检测到特定对象时上传图片
    """
    from maix import camera, display, image, nn, app
    import os
    
    # 七牛云配置信息
    ACCESS_KEY = "KgCzxHSGM7pTsrTZbQptzoow42e5IcFOMeFrIoQz"
    SECRET_KEY = "xcloaEa4X3XzqXKDmz_1U1AFtNI1jlbodaHoNOQ4"
    BUCKET_NAME = "hongkongidcard"
    DOMAIN = "hongkongidcard.wenfree.cn"
    
    # 初始化七牛云上传器
    uploader = QiniuUploader(ACCESS_KEY, SECRET_KEY, BUCKET_NAME, DOMAIN)
    
    # 初始化摄像头和模型
    model_path = "/root/models/yolov5s.mud"
    if not os.path.exists(model_path):
        print("模型文件不存在，请先运行 download_models.py")
        return
        
    detector = nn.YOLOv5(model=model_path)
    cam = camera.Camera(640, 480, detector.input_format())
    dis = display.Display()
    
    frame_count = 0
    
    while not app.need_exit():
        img = cam.read()
        objs = detector.detect(img, conf_th=0.5, iou_th=0.45)
        
        # 显示检测结果
        for obj in objs:
            img.draw_rect(obj.x, obj.y, obj.w, obj.h, image.COLOR_RED, 2)
            
        dis.show(img)
        
        # 每30帧上传一次图片（约每秒一次，假设30fps）
        frame_count += 1
        if frame_count >= 30:
            frame_count = 0
            
            # 保存当前帧到临时文件
            temp_image_path = "/tmp/current_frame.jpg"
            img.save(temp_image_path)
            
            # 使用固定名称上传图片，实现覆盖模式
            result = uploader.upload_image(temp_image_path, "latest_frame")
            if result["success"]:
                print(f"图片上传成功: {result['key']}")
                print(f"访问地址: {result['url']}")
            else:
                print(f"图片上传失败: {result['error']}")
                
            # 删除临时文件
            try:
                os.remove(temp_image_path)
            except:
                pass

if __name__ == "__main__":
    # 运行基本示例
    example()
    
    # 如果要运行与摄像头集成的示例，请取消下面一行的注释
    integrate_with_camera_example()